package com.marketlive.entity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.hibernate.usertype.UserType;
import org.hibernate.HibernateException;
import org.hibernate.Hibernate;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.io.Serializable;

/**
 * Maps {@link IntegerPk} to a SQL integer type in the database.
 */
public class IntegerPkType implements UserType, Serializable {

    /**
     * Logger.
     */
    private static Log log = LogFactory.getLog(IntegerPkType.class);

    /**
     * The entity type for <code>IntegerPkType</code>s.
     */
    private final String entityType;

    /**
     * Default constructor. Initializes entity type to "XXX".
     */
    public IntegerPkType() {
        this.entityType = "XXX";
    }

    /**
     * Constructor that fully initializes an <code>IntegerPkType</code>.
     *
     * @param entityType the entityType of this <code>IntegerPkType</code>
     */
    public IntegerPkType(String entityType) {
        this.entityType = entityType;
    }

    /**
     * Return the SQL type codes for the columns mapped by this type.
     * The codes are defined in java.sql.Types.
     * @return a one-element array containing the value java.sql.Types.INTEGER
     * @see java.sql.Types
     */
    public int[] sqlTypes() {
        return new int[]{java.sql.Types.INTEGER};
    }

    /**
     * Returns the class that is returned by <code>nullSafeGet()</code>.
     *
     * @return the <code>IntegerPk</code> class
     */
    public Class returnedClass() {
        return IntegerPk.class;
    }

    /**
     * Compares two instances of the class mapped by this type for persistence equality.
     * If the two instances are null or the same, returns true. If one instance is null
     * and the other is not, returns false. If none of these conditions apply, delegates
     * to <code>x.equals(y)</code>.
     *
     * @param x first object to compare
     * @param y second object to compare
     * @return true if the two objects represent the same entity
     * @throws org.hibernate.HibernateException if the operation fails
     */
    public boolean equals(final Object x, final Object y)
            throws HibernateException {
        if (x == y) {
            return true;
        }
        if (x == null) {
            return false;
        }
        return x.equals(y);
    }

    /**
     * Retrieves an <code>IntegerPk</code> from a JDBC ResultSet.
     *
     * @param resultSet the result set to examine
     * @param names an array of column names. Only the first element in the array is used.
     * @param o not used
     * @return an <code>IntegerPk</code> from the given result set, or null if none was found
     * @throws org.hibernate.HibernateException if an error occurs
     * @throws java.sql.SQLException if an error occurs
     */
    public Object nullSafeGet(final ResultSet resultSet, final String[] names, final Object o)
            throws HibernateException, SQLException {
        Integer id = (Integer) Hibernate.INTEGER.nullSafeGet(resultSet, names[0]);

        if (id == null) {
            return null;
        } else {
            return new IntegerPk(entityType, id.intValue());
        }
    }

    /**
     * Sets the given value as a query parameter on the given statement.
     *
     * @param st the statement to set the value for
     * @param value the value to set
     * @param index the index in the statement to which the value corresponds
     * @throws org.hibernate.HibernateException if an error occurs
     * @throws java.sql.SQLException if an error occurs
     * @see org.hibernate.UserType
     */
    public void nullSafeSet(final PreparedStatement st, final Object value, final int index)
            throws HibernateException, SQLException {
        if (value == null) {
            Hibernate.INTEGER.nullSafeSet(st, value, index);
        } else {
            IntegerPk pk = (IntegerPk) value;
            Hibernate.INTEGER.nullSafeSet(st, new Integer(pk.getEntityID()), index);
        }
    }

    /**
     * Returns a copy of the given key. Because IntegerPk is immutable, this
     * implementation returns a reference to the original object.
     *
     * @param integerPk the object to copy. Must be an <code>IntegerPk</code>.
     * @return a reference to the given object
     * @throws HibernateException if the given object is not an instance of <code>IntegerPk</code>
     */
    public Object deepCopy(final Object integerPk) throws HibernateException {
        if (integerPk != null) {
            if (!(integerPk instanceof IntegerPk)) {
                throw new HibernateException("Object must be an instance of IntegerPk: " + integerPk);
            }
        }
        return integerPk;
    }

    /**
     * Returns false. <code>IntegerPk</code>s are immutable.
     *
     * @return false
     */
    public boolean isMutable() {
        return false;
    }

    /**
     * Returns a hash code for the given object that is consistent with persistence equality.
     *
     * @param pIntegerPk the object for which to return a hash code
     * @return the hash code of the given object
     * @throws NullPointerException if <code>pIntegerPk</code> is null
     */
    public int hashCode(Object pIntegerPk) throws HibernateException {
        return pIntegerPk.hashCode();
    }

    /**
     * Transforms the given object into a cacheable representation.
     * Casts the given object to <code>Serializable</code>.
     *
     * @param pIntegerPk the object to transform
     * @return a cacheable form of the given object
     * @throws HibernateException if an error occurs
     */
    public Serializable disassemble(Object pIntegerPk) throws HibernateException {
        return (Serializable)pIntegerPk;
    }

    /**
     * Reconstructs an object from its cacheable representation.
     * @param pCached the object to assemble
     * @param pOwner the owner. Not used.
     * @return a reference to <code>pCached</code>
     * @throws HibernateException if an error occurs
     */
    public Object assemble(Serializable pCached, Object pOwner) throws HibernateException {
        return pCached;
    }

    /**
     * Returns the original object.
     *
     * @param pOriginal the original object to merge into the target
     * @param pTarget the target object. Not used.
     * @param pOwner the owner of the object. Not used.
     * @return a reference to <code>pOriginal</code>
     */
    public Object replace(Object pOriginal, Object pTarget, Object pOwner) throws HibernateException {
        return pOriginal;
    }
}
